package com.cs.base.quartz.core;

import com.cs.base.quartz.support.TaskInfoEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.hibernate.service.spi.ServiceException;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;

/**
 * quartz管理器
 *
 * @author wangjiahao
 * @version 1.0
 * @className QuartzManager
 * @since 2019-03-25 14:35
 */
@Slf4j
@Component
public class QuartzManager {

    @Autowired
    private Scheduler scheduler;

    /**
     * 查询所有任务
     *
     * @return
     */
    public List<TaskInfoEntity> queryJobList() {
        List<TaskInfoEntity> list = new ArrayList<>();
        try {
            for (String groupJob : scheduler.getJobGroupNames()) {
                for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.<JobKey>groupEquals(groupJob))) {
                    List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
                    for (Trigger trigger : triggers) {
                        Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
                        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
                        String cronExpression = "";
                        String createTime = "";
                        String milliSeconds = "";
                        String repeatCount = "";
                        String startDate = "";
                        String endDate = "";
                        if (trigger instanceof CronTrigger) {
                            CronTrigger cronTrigger = (CronTrigger) trigger;
                            cronExpression = cronTrigger.getCronExpression();
                            createTime = cronTrigger.getDescription();
                        } else if (trigger instanceof SimpleTrigger) {
                            SimpleTrigger simpleTrigger = (SimpleTrigger) trigger;
                            milliSeconds = simpleTrigger.getRepeatInterval() + "";
                            repeatCount = simpleTrigger.getRepeatCount() + "";
                            startDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(simpleTrigger.getStartTime());
                            endDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(simpleTrigger.getEndTime());
                        }
                        TaskInfoEntity info = new TaskInfoEntity();
                        info.setJobClassName(jobKey.getName());
                        info.setJobGroup(jobKey.getGroup());
                        info.setJobDescription(jobDetail.getDescription());
                        info.setJobStatus(triggerState.name());
                        info.setCronExpression(cronExpression);
                        info.setCreateTime(createTime);

                        info.setRepeatCount(repeatCount);
                        info.setStartDate(startDate);
                        info.setMilliSeconds(milliSeconds);
                        info.setEndDate(endDate);
                        list.add(info);
                    }
                }
            }
            log.info("任务的数量为：{}", list.size());
        } catch (SchedulerException e) {
            log.info("查询任务失败", e.getMessage());
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 设置普通定时任务
     *
     * @param info
     * @throws ParseException
     */
    public void setSimpleTriggerJob(TaskInfoEntity info) throws ParseException {
        String jobName = info.getJobClassName();
        String jobGroup = info.getJobGroup();
        String jobDescription = info.getJobDescription();
        Long milliSeconds = Long.parseLong(info.getMilliSeconds());
        Integer repeatCount = Integer.parseInt(info.getRepeatCount());
        Date startDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(info.getStartDate());
        Date endDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(info.getEndDate());
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
            if (checkExists(jobName, jobGroup)) {
                log.error("AddJob fail, job already exist, jobGroup:{}, jobName:{}", jobGroup, jobName);
                throw new ServiceException(String.format("Job已经存在, jobName:{},jobGroup:{}", jobName, jobGroup));
            }
            /* 简单调度 */
            SimpleTrigger trigger = TriggerBuilder
                    .newTrigger()
                    .withIdentity(triggerKey)
                    .startAt(startDate)
                    .withSchedule(
                            SimpleScheduleBuilder.simpleSchedule()
                                    .withIntervalInMilliseconds(milliSeconds)
                                    .withRepeatCount(repeatCount))
                    .endAt(endDate).build();
            Class<? extends Job> clazz = (Class<? extends Job>) Class.forName(jobName);
            JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(jobKey)
                    .withDescription(jobDescription).build();
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException | ClassNotFoundException e) {
            log.info("简单调度任务添加失败", e.getMessage());
            throw new ServiceException("简单调度任务添加失败！");
        }
    }

    /**
     * 添加定时任务
     *
     * @param info
     */
    public void addJob(TaskInfoEntity info) {
        String jobName = info.getJobClassName();
        String jobGroup = info.getJobGroup();
        String cronExpression = info.getCronExpression();
        String jobDescription = info.getJobDescription();
        String createTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
        try {
            if (checkExists(jobName, jobGroup)) {
                log.error("AddJob fail, job already exist, jobGroup:{}, jobName:{}", jobGroup, jobName);
                throw new ServiceException(String.format("Job已经存在, jobName:{},jobGroup:{}", jobName, jobGroup));
            }

            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            JobKey jobKey = JobKey.jobKey(jobName, jobGroup);

            CronScheduleBuilder schedBuilder = CronScheduleBuilder
                    .cronSchedule(cronExpression)
                    .withMisfireHandlingInstructionDoNothing();
            CronTrigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(triggerKey).withDescription(createTime)
                    .withSchedule(schedBuilder).build();

            Class<? extends Job> clazz = (Class<? extends Job>) Class.forName(jobName);
            JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(jobKey)
                    .withDescription(jobDescription).build();
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException | ClassNotFoundException e) {
            log.error("保存定时复杂调度任务失败", e.getMessage());
            throw new ServiceException("保存定时复杂调度任务失败");
        }
    }

    /**
     * 修改定时任务
     *
     * @param info
     */
    public void editJob(TaskInfoEntity info) {
        String jobName = info.getJobClassName();
        String jobGroup = info.getJobGroup();
        String cronExpression = info.getCronExpression();
        String jobDescription = info.getJobDescription();
        String createTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
        try {
            if (!checkExists(jobName, jobGroup)) {
                throw new ServiceException(String.format("Job不存在, jobName:{},jobGroup:{}", jobName, jobGroup));
            }
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            JobKey jobKey = new JobKey(jobName, jobGroup);
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder
                    .cronSchedule(cronExpression)
                    .withMisfireHandlingInstructionDoNothing();
            CronTrigger cronTrigger = TriggerBuilder.newTrigger()
                    .withIdentity(triggerKey).withDescription(createTime)
                    .withSchedule(cronScheduleBuilder).build();

            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            jobDetail.getJobBuilder().withDescription(jobDescription);
            HashSet<Trigger> triggerSet = new HashSet<>();
            triggerSet.add(cronTrigger);

            scheduler.scheduleJob(jobDetail, triggerSet, true);
        } catch (SchedulerException e) {
            log.error("修改定时任务失败", e.getMessage());
            throw new ServiceException("修改定时任务失败");
        }
    }

    /**
     * 删除定时任务
     * @param jobName
     * @param jobGroup
     */
    public void deleteJob(String jobName, String jobGroup) {
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        try {
            if (checkExists(jobName, jobGroup)) {
                scheduler.pauseTrigger(triggerKey);
                scheduler.unscheduleJob(triggerKey);
                log.info("delete, triggerKey:{}", triggerKey);
            }
        } catch (SchedulerException e) {
            log.error("删除定时任务失败",e.getMessage());
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 暂停定时任务
     * @param jobName
     * @param jobGroup
     */
    public void pauseJob(String jobName, String jobGroup) {
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        try {
            if (checkExists(jobName, jobGroup)) {
                scheduler.pauseTrigger(triggerKey);
                log.info("Pause success, triggerKey:{}", triggerKey);
            }
        } catch (SchedulerException e) {
            log.info("暂停定时任务失败",e.getMessage());
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 恢复已暂停的定时任务
     * @param jobName
     * @param jobGroup
     */
    public void resumeJob(String jobName, String jobGroup) {
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        try {
            if (checkExists(jobName, jobGroup)) {
                scheduler.resumeTrigger(triggerKey);
                log.info("Resume success, triggerKey:{}", triggerKey);
            }
        } catch (SchedulerException e) {
            log.error("恢复定时任务失败",e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 检查是否存在定时任务
     * @param jobName
     * @param jobGroup
     * @return
     * @throws SchedulerException
     */
    private boolean checkExists(String jobName, String jobGroup)
            throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
        return scheduler.checkExists(triggerKey);
    }




}
